###############################################################################
# SuperLinks                                                                  #
# Copyright (c) 2000-2007 Greg Nolle (http://greg.nolle.co.uk)                #
###############################################################################
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of the GNU General Public License as published by the Free  #
# Software Foundation; either version 2 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #
# more details.                                                               ##                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 #
###############################################################################
# Add.pm.pl -> Add module                                                     #
###############################################################################
# DON'T EDIT BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!                         #
###############################################################################
package Add;

BEGIN { require "System.pm.pl"; import System qw($SYSTEM); }
BEGIN { require "General.pm.pl"; import General qw($GENERAL); }
require "Error.pm.pl";
require "Standard.pm.pl";
require "Mail.pm.pl";
require "StaticPages.pm.pl";
require "HashToString.pm.pl";

use File::Copy;
use URI;
use strict;

require "Output/Add.pm.pl";

sub new {
  my ($class) = @_;
  my $self    = {};
  return bless($self, $class);
}

sub DESTROY { }

###############################################################################
# show subroutine
sub show {
  my $self = shift;
  my %in = (DB => undef, ERROR => "", @_);

  #----------------------------------------------------------------------#
  # Getting data...                                                      #

  my ($Categories, $CategoriesIndex) = $in{'DB'}->Query(
    TABLE   => "Categories",
    WHERE   => {
      USER_ADD  => ["1"]
    },
    SORT    => "FULL_TITLE",
    BY      => "A-Z"
  );

  my %INPUT;

  $INPUT{'CATEGORIES'} = $Categories;

  #----------------------------------------------------------------------#
  # Printing page...                                                     #

  my $Skin = Skin::Add->new();

  &Standard::PrintHTMLHeader();
  print $Skin->show(input => \%INPUT, error => $in{'ERROR'});
  
  return 1;
}

###############################################################################
# do subroutine
sub do {
  my $self = shift;
  my %in = (DB => undef, @_);

  #----------------------------------------------------------------------#
  # Checking fields...                                                   #

  my @Fields = (
    { name => "TITLE"        , required => 1, size => $GENERAL->{'SIZE_TITLE'} },
    { name => "URL"          , required => 1, size => 256 },
    { name => "CATEGORY"     , required => 1              },
    { name => "DESCRIPTION"  , required => 0, size => $GENERAL->{'SIZE_DESCRIPTION'} },
    { name => "KEYWORDS"     , required => 1, size => $GENERAL->{'SIZE_KEYWORDS'} },
    { name => "CONTACT_NAME" , required => 1, size => 128 },
    { name => "CONTACT_EMAIL", required => 1, size => 128 },
    { name => "SHOW_EMAIL"   , required => 0              },
    { name => "MAILING_LIST" , required => 0              },
    { name => "PASSWORD"     , required => 1, size => 64  }
  );

  my (%RECORD, %EXTRA, %INPUT, @Error);

  foreach my $field (@Fields) {
    if ($field->{'required'} && $SL::QUERY{'FORM_'.$field->{'name'}} eq "") {
      push(@Error, "MISSING-".$field->{'name'});
    } elsif ($field->{'size'} && $SL::QUERY{'FORM_'.$field->{'name'}} ne "" && length($SL::QUERY{'FORM_'.$field->{'name'}}) > $field->{'size'}) {
      push(@Error, "TOOLONG-".$field->{'name'});
    } else {
      $RECORD{ $field->{'name'} } = $SL::QUERY{'FORM_'.$field->{'name'}};
    }
  }

  foreach my $field (@{ $GENERAL->{'RESOURCE_EXTRA'} }) {
    next unless ($field->{'PUBLIC'});
    if ($field->{'REQUIRED'} && $SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}} eq "") {
      push(@Error, "MISSING-EXTRA_".$field->{'ID'});
    } elsif ($field->{'SIZE'} && $SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}} ne "" && length($SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}}) > $field->{'SIZE'}) {
      push(@Error, "TOOLONG-EXTRA_".$field->{'ID'});
    } elsif ($field->{'CHECKSUB'}) {
      my $Sub = eval("sub { my (\$Input) = \@_; $field->{'CHECKSUB'} }");
      &Error::Error("CP", MESSAGE => "Error evaluating checking subroutine. $@") if ($@);
      my $error = &$Sub($SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}});
      if ($error == 1) {
        $EXTRA{ $field->{'ID'} } = $SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}};
      } else {
        push(@Error, $error);
      }
    } else {
      $EXTRA{ $field->{'ID'} } = $SL::QUERY{'FORM_EXTRA_'.$field->{'ID'}};
    }
  }

  if ($RECORD{'URL'} && $RECORD{'URL'} !~ /^http(s)?:\/\/.+/i && $RECORD{'URL'} !~ /^ftp:\/\/.+/i) {
    push(@Error, "INVALID-URL");
  }
  
  if ($RECORD{'CONTACT_EMAIL'} && $RECORD{'CONTACT_EMAIL'} !~ /[\.\w\-]+\@[\.\w\-]+\.[\w\-]+/) {
    push(@Error, "INVALID-CONTACT_EMAIL");
  }
  
  if (!$SL::QUERY{'FORM_PASSWORD2'}) {
    push(@Error, "MISSING-PASSWORD2");
  } elsif ($RECORD{'PASSWORD'} ne $SL::QUERY{'FORM_PASSWORD2'}) {
    push(@Error, "PASSWORDS-DONT-MATCH");
  }
  
  if ($RECORD{'CATEGORY'}) {
    my $category = $in{'DB'}->BinarySelect(
      TABLE   => "Categories",
      KEY     => $RECORD{'CATEGORY'}
    );
    if ($category && $category->{'USER_ADD'}) {
      $INPUT{'CATEGORY'} = $category;
    } else {
      push(@Error, "INVALID-CATEGORY");
    }
  }
  
  if ($RECORD{'URL'}) {
    my $URI = URI->new($RECORD{'URL'});
    my @Segments = $URI->path_segments();
    my $file = (scalar(@Segments) >= 1 ? pop(@Segments) : "");
    my ($filename, $extension) = ($file =~ m/^(.*)\.(.*?)$/);

    my %where;
    $where{'URL_PROTOCOL'}  = [$URI->scheme()] if ($GENERAL->{'CHECK_DUPLICATE_PROTOCOL'});
    $where{'URL_HOST'}      = [$URI->host()] if ($GENERAL->{'CHECK_DUPLICATE_HOST'});
    $where{'URL_PORT'}      = [$URI->port()] if ($GENERAL->{'CHECK_DUPLICATE_PORT'});
    $where{'URL_DIRECTORY'} = [join("/", @Segments)] if ($GENERAL->{'CHECK_DUPLICATE_DIRECTORY'} && scalar(@Segments) >= 1);
    $where{'URL_FILENAME'}  = [$filename] if ($GENERAL->{'CHECK_DUPLICATE_FILENAME'} && $filename);
    $where{'URL_EXTENSION'} = [$extension] if ($GENERAL->{'CHECK_DUPLICATE_EXTENSION'} && $extension);
    $where{'URL_QUERY'}     = [$URI->query()] if ($GENERAL->{'CHECK_DUPLICATE_QUERY'} && $URI->query());
    
    if (scalar(keys %where) >= 1) {
      my $resources = $in{'DB'}->Query(
        TABLE   => "Resources",
        WHERE   => \%where,
        MATCH   => "ALL",
        COUNT   => 1
      );
      if ($resources) {
        if ($GENERAL->{'CHECK_DUPLICATE_ACTION'} eq "FLAG") {
          $RECORD{'FLAGS'} = "DUPLICATE";
        } else {
          push(@Error, "ALREADYEXISTS-URL");
        }
      }
    }
  }
  
  if ($RECORD{'URL'}) {
    foreach my $url (@{ $GENERAL->{'BAN_URLS'} }) {
      push(@Error, "BANNED-URL") and last if ($RECORD{'URL'} =~ /$url/i);
    }
  }

  foreach my $ip (@{ $GENERAL->{'BAN_IPS'} }) {
    push(@Error, "BANNED-IP") and last if ($ENV{'REMOTE_ADDR'} =~ /^$ip/);
  }

  if ($SL::QUERY{'FORM_IMAGE_TYPE'} eq "URL" && $GENERAL->{'IMAGE_URL'}) {
    push(@Error, "MISSING-IMAGE_URL") if ($SL::QUERY{'FORM_IMAGE_URL'} eq "" || $SL::QUERY{'FORM_IMAGE_URL'} eq "http://");
    push(@Error, "TOOLONG-IMAGE_URL") if (length($SL::QUERY{'FORM_IMAGE_URL'}) > 512);
    $RECORD{'IMAGE'} = $SL::QUERY{'FORM_IMAGE_URL'};
  } elsif ($SL::QUERY{'FORM_IMAGE_TYPE'} eq "UPLOAD" && $GENERAL->{'IMAGE_UPLOAD'}) {
    my $file     = $SL::CGI->param('FORM_IMAGE_UPLOAD');
    my $tempfile = $SL::CGI->tmpFileName($file);
    
    {
      (push(@Error, "MISSING-IMAGE_UPLOAD") and last) unless ($file && $tempfile && -e $tempfile);
      (push(@Error, "INVALID-IMAGE_UPLOAD_SIZE") and last) unless (-s $tempfile <= ($GENERAL->{'UPLOAD_MAXSIZE'} * 1024));
      (push(@Error, "INVALID-IMAGE_UPLOAD_TYPE") and last) unless ($SL::CGI->uploadInfo($file)->{'Content-Type'} =~ /^image\//i);

      $file =~ m/\.(.*?)$/;
      my $ext  = $1;
      my $exts = &Standard::ArrayToHash($GENERAL->{'UPLOAD_EXTENSIONS'});
      (push(@Error, "INVALID-IMAGE_UPLOAD_EXT") and last) unless ($exts->{$ext});

      use Image::Size;
      my ($width, $height) = imgsize($tempfile);
      (push(@Error, "INVALID-IMAGE_UPLOAD_DIM") and last) unless ($width <= $GENERAL->{'UPLOAD_MAXWIDTH'} && $height <= $GENERAL->{'UPLOAD_MAXHEIGHT'});
    }
  }
    
CONT:

  if (scalar(@Error) >= 1) {
    $self->show(DB => $in{'DB'}, ERROR => \@Error);
    return 1;
  }

  #----------------------------------------------------------------------#
  # Inserting data...                                                    #

  $RECORD{'STATUS'}        = 1 unless ($GENERAL->{'VALIDATE_NEW_RESOURCES'});
  $RECORD{'CREATE_SECOND'} = time;
  $RECORD{'CREATE_DATE'}   = &Standard::ConvertEpochToDate($RECORD{'CREATE_SECOND'});
  $RECORD{'CREATE_TIME'}   = &Standard::ConvertEpochToTime($RECORD{'CREATE_TIME'});
  $RECORD{'UPDATE_SECOND'} = $RECORD{'CREATE_SECOND'};
  $RECORD{'UPDATE_DATE'}   = $RECORD{'CREATE_DATE'};
  $RECORD{'UPDATE_TIME'}   = $RECORD{'CREATE_TIME'};

  my $URI = URI->new($RECORD{'URL'});
  my @Segments = $URI->path_segments();
  my $file = pop(@Segments);
  my ($filename, $extension) = ($file =~ m/^(.*)\.(.*?)$/);
  
  $RECORD{'URL_PROTOCOL'}  = $URI->scheme();
  $RECORD{'URL_HOST'}      = $URI->host();
  $RECORD{'URL_PORT'}      = $URI->port();
  $RECORD{'URL_DIRECTORY'} = join("/", @Segments);
  $RECORD{'URL_FILENAME'}  = $filename;
  $RECORD{'URL_EXTENSION'} = $extension;
  $RECORD{'URL_QUERY'}     = $URI->query();
  
  $RECORD{'TITLE'}         = &Standard::HTMLize($RECORD{'TITLE'});
  $RECORD{'DESCRIPTION'}   = &Standard::HTMLize($RECORD{'DESCRIPTION'});
  $RECORD{'KEYWORDS'}      = &Standard::HTMLize($RECORD{'KEYWORDS'});
  $RECORD{'CONTACT_NAME'}  = &Standard::HTMLize($RECORD{'CONTACT_NAME'});
  $RECORD{'TITLE'}         = &Standard::FilterWords($RECORD{'TITLE'});
  $RECORD{'DESCRIPTION'}   = &Standard::FilterWords($RECORD{'DESCRIPTION'});
  $RECORD{'KEYWORDS'}      = &Standard::FilterWords($RECORD{'KEYWORDS'});
  $RECORD{'CONTACT_NAME'}  = &Standard::FilterWords($RECORD{'CONTACT_NAME'});

  my $HashToString = HashToString->new();
  $RECORD{'EXTRA'}         = $HashToString->Write(\%EXTRA);

  (
    $RECORD{'ID'} = $in{'DB'}->Insert(
      TABLE   => "Resources",
      VALUES  => \%RECORD
    )
  ) || &Error::Error("SL", MESSAGE => "Error inserting record. $in{'DB'}->{'ERROR'}");

  $RECORD{'extra'} = \%EXTRA;
  $INPUT{'RECORD'} = \%RECORD;

  if ($RECORD{'STATUS'}) {
    (
      $in{'DB'}->Update(
        TABLE   => "Categories",
        VALUES  => {
          RESOURCES => "++\${RESOURCES}"
        },
        KEY     => $RECORD{'CATEGORY'}
      )
    ) || &Error::Error("SL", MESSAGE => "Error updating record. $in{'DB'}->{'ERROR'}");
    
    my $StaticPages = StaticPages->new(DB => $in{'DB'});
       $StaticPages->Update(TYPE => "Detail", INPUT => \%RECORD)
         || &Error::Error("SL", MESSAGE => "Error updating static pages. $StaticPages->{'ERROR'}");
  }

  if ($SL::QUERY{'FORM_IMAGE_TYPE'} eq "UPLOAD" && $GENERAL->{'IMAGE_UPLOAD'}) {
    my $file     = $SL::CGI->param('FORM_IMAGE_UPLOAD');
       $file     =~ m/\.(.*?)$/;
    my $ext      = $1;
    my $tempfile = $SL::CGI->tmpFileName($file);

    copy($tempfile, "$SYSTEM->{'PUBLIC_PATH'}/Upload/$RECORD{'ID'}.$ext") || &Error::CGIError("Error copying upload temporary file. $!", $tempfile);
    
    $RECORD{'IMAGE'}           = "$SYSTEM->{'PUBLIC_URL'}/Upload/$RECORD{'ID'}.$ext";
    $RECORD{'UPLOAD_FILENAME'} = "$RECORD{'ID'}.$ext";
    
    (
      $in{'DB'}->Update(
        TABLE   => "Resources",
        VALUES  => {
          IMAGE           => $RECORD{'IMAGE'},
          UPLOAD_FILENAME => $RECORD{'UPLOAD_FILENAME'}
        },
        KEY     => $RECORD{'ID'}
      )
    ) || &Error::Error("SL", MESSAGE => "Error updating record. $in{'DB'}->{'ERROR'}");
  }

  my $Skin = Skin::Add->new();

  if ($GENERAL->{'NOTIFY_ADMIN_OF_ADD'}) {
    my %Message = $Skin->email(type => "admin", input => \%INPUT);
    my $Mail = Mail->new();
       $Mail->Send(%Message) || &Error::Error("SL", MESSAGE => "Error sending email to admin. $Mail->{'ERROR'}");
  }
  if ($GENERAL->{'NOTIFY_USER_OF_ADD'}) {
    my %Message = $Skin->email(type => "user", input => \%INPUT);
    my $Mail = Mail->new();
       $Mail->Send(%Message) || &Error::Error("SL", MESSAGE => "Error sending email to admin. $Mail->{'ERROR'}");
  }

  #----------------------------------------------------------------------#
  # Printing page...                                                     #

  &Standard::PrintHTMLHeader();
  print $Skin->do(input => \%INPUT);
  
  return 1;
}

1;